/*
 MAXCLIENT-ben definiált maximális számú klienssel összeköttetést képes létesíteni
A klienseket láncolt listában tárolja
Kilépő klienseket helyesen lekezeli, a láncolt listából törli
a kliensektől előjeles egész számokat vár, bármely más (kivétel “?” karakter) esetén hibaüzenetet küld a kliensnek
- 	a számot hozzáadja egy globális számlálóhoz, és a klienshez tartozó számlálóhoz is

-	“?” karakter érkezése esetén visszaadja a globális számláló és a kliensekhez tartozó számlálók értékét

+1 jegy:
Parancssori argumentumként megadható egy pozitív egész szám, mely a számlálók számrendszerének alapját jelentse!
Pl. ha ez 2, és a kliens 8-at írt be első értékként, akkor a kliens 1000-t fog kiírni.

+ 1 jegy:
Minden megkapott érték esetén a szerver saját magának írja ki, hogy az adott érték milyen IP-ről és portról jött.

+ 1 jegy:
A szerver a következő formátumban fogadjon el számokat a kliensektől az alapértelmezett
– eddig használt – decimális megoldás mellett: OCT, HEX, BIN.
Az adott „parancs” után szereplő számot a parancsnak megfelelő számrendszerben
reprezentált értékként kezeljen a szerver!
Pl. ha tízes számrendszerben kell kiírnia a szervernek az értékeket,
a globális számlálóban eddig a decimális 54 érték van, továbbá egy klienstől a „BIN 101” parancs érkezett,
akkor ezután érkező „?” parancsra a globális számláló kiírt értéke 59 lesz.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>

#define MAXCLIENT 2
struct kliens{
	int fd;
	int sum;
	char ip[INET6_ADDRSTRLEN];
	char port[6];
	struct kliens* next;
};
struct kliens* kliensek=NULL;
int kliensSzam=0;

#define listenport "2222"
int listenSocket=-1;
fd_set master;
int fdmax;

int gsum=0;
char szerverszamrendszer[2]="10";

void klienshozzaad(int newfd, struct sockaddr sa){
	FD_SET(newfd,&master);
	if (newfd>fdmax) {
		fdmax=newfd;
	}
	struct kliens* kl=(struct kliens*)malloc(sizeof(struct kliens));

	kl->fd=newfd;
	kl->sum=0;
	inet_ntop(sa.sa_family,&(((struct sockaddr_in*)&sa)->sin_addr),kl->ip,INET6_ADDRSTRLEN);
	int p=ntohs(((struct sockaddr_in*)&sa)->sin_port);
	sprintf(kl->port,"%d",p);
	kl->next=kliensek;

	kliensek=kl;

	kliensSzam++;
}

void klienstorol(int i){
	FD_CLR(i,&master);
	int j;
	int tempfdmax=0;
	for (j = 0; j <= fdmax; ++j) {
		if (FD_ISSET(j,&master)) {
			tempfdmax=j;
		}
	}
	fdmax=tempfdmax;

	struct kliens* torlendo=kliensek;
	if (kliensek->fd==i) {
		kliensek=kliensek->next;
	} else {
		struct kliens* elozo=kliensek;
		torlendo=kliensek->next;
		while(torlendo->fd!=i){
			elozo=torlendo;
			torlendo=torlendo->next;
		}
	}
	printf("torolt: %d\n",torlendo->fd);
	fflush(stdout);
	free(torlendo);
	close(i);
	kliensSzam--;
}

void atvalt(char inszamrendszer[],char outszamrendszer[], char mit[],char data[]){
	char shcommand[200]="echo 'obase=";
	strcat(shcommand,outszamrendszer);
	strcat(shcommand,";ibase=");
	strcat(shcommand,inszamrendszer);
	strcat(shcommand,";");
	strcat(shcommand,mit);
	strcat(shcommand,"' | bc");
	FILE *fp;
	fp = popen(shcommand,"r");
	fgets(data, 40 , fp);
	pclose(fp);

}

void kliensinp(int i){
	struct kliens* kl=kliensek;
	while(kl->fd!=i){
		kl=kl->next;
	}

	char ibuff[100];
	char buff[100];
	memset(buff, '\0', 100);
	memset(ibuff, '\0', 100);

	int readedbytes=recv(i,ibuff,sizeof buff,0);

	if (readedbytes<=0) {
		klienstorol(i);
	} else {

		if (strncmp(ibuff,"\r\n",2)==0) {
			return;
		}
		int j;
		for (j = 0; j < readedbytes-2; ++j) {
			buff[j]=ibuff[j];
		}
		if (strncmp(buff,"q",1)==0) {
			klienstorol(i);
			return;
		}
		if (strncmp(buff,"?",1)==0) {
			char uz[100]="";

			snprintf(uz,sizeof uz, "client sum: %d\nglobal sum: %d\n",kl->sum,gsum);
			send(kl->fd,uz,sizeof uz,0);
			return;
		}


		char kliensszamrendszer[]="10";

		if (strncmp(buff,"OCT ",4)==0) {
			strcpy(kliensszamrendszer,"8");
			memset(buff, '\0', 100);
			memcpy( buff, &ibuff[4], strlen(ibuff)-2-4 );
		}
		if (strncmp(buff,"HEX ",4)==0) {
			strcpy(kliensszamrendszer,"16");
			memset(buff, '\0', 100);
			memcpy( buff, &ibuff[4], strlen(ibuff)-2-4 );
		}
		if (strncmp(buff,"BIN ",4)==0) {
			strcpy(kliensszamrendszer,"2");
			memset(buff, '\0', 100);
			memcpy( buff, &ibuff[4], strlen(ibuff)-2-4 );
		}

		int joszam=1;
		for (j = 0; j < strlen(buff); ++j) {
			if (buff[j]=='-' && j==0) {
				break;
			}
			if ((strncmp(kliensszamrendszer,"2",1)==0)) {
				if (buff[j]!='0' && buff[j]!='1' ) {
					joszam=0;
				}
			}
			if ((strncmp(kliensszamrendszer,"8",1)==0)) {
				if (buff[j]!='0' && buff[j]!='1' && buff[j]!='2' && buff[j]!='3' && buff[j]!='4' && buff[j]!='5' && buff[j]!='6' && buff[j]!='7' ) {
					joszam=0;
				}
			}
			if ((strncmp(kliensszamrendszer,"10",2)==0)) {
				if (buff[j]!='0' && buff[j]!='1' && buff[j]!='2' && buff[j]!='3' && buff[j]!='4' && buff[j]!='5' && buff[j]!='6' && buff[j]!='7' && buff[j]!='8' && buff[j]!='9') {
					joszam=0;
				}
			}
			if ((strncmp(kliensszamrendszer,"16",2)==0)) {
				if (buff[j]!='0' && buff[j]!='1' && buff[j]!='2' && buff[j]!='3' && buff[j]!='4' && buff[j]!='5' && buff[j]!='6' && buff[j]!='7' && buff[j]!='8' && buff[j]!='9' && buff[j]!='A' && buff[j]!='B' && buff[j]!='C' && buff[j]!='D' && buff[j]!='E' && buff[j]!='F') {
					joszam=0;
				}
			}
		}

		if(joszam){
			printf("client: %s:%s ertek: ",kl->ip,kl->port);
			fflush(stdout);
			char data[40];
			atvalt(kliensszamrendszer,szerverszamrendszer,buff,data);
			fprintf(stdout, "%s",data);
			fflush(stdout);

			atvalt(kliensszamrendszer,"10",buff,data);
			int szam=atoi(data);
			kl->sum+=szam;
			gsum+=szam;
		}
		else{
			char uz[100]="nem jo szam!\n";
			send(kl->fd,uz,sizeof uz,0);
			return;
		}
	}
}

void processloop(){
	struct sockaddr kladdr;
	fd_set readfd;
	FD_ZERO(&readfd);
	struct timeval tv;
	tv.tv_sec=1;
	tv.tv_usec=0;
	while(1){
		readfd=master;
		select(fdmax+1,&readfd,NULL,NULL,&tv);
		int i;
		for (i = 0; i <= fdmax; ++i) {
			if (FD_ISSET(i,&readfd)) {
				if (i==listenSocket) {
					socklen_t kladdrlen=sizeof kladdr;
					int newfd=accept(listenSocket,&kladdr,&kladdrlen);
					if (kliensSzam<MAXCLIENT) {
						klienshozzaad(newfd,kladdr);
					} else {
						char uz[]="limit\n";
						send(newfd,uz,sizeof uz,0);
						close(newfd);
					}
				} else {
					kliensinp(i);
				}
			}
		}
	}
}

void serverlisten(){
	struct addrinfo krit;
	struct addrinfo* res;
	memset(&krit,0,sizeof krit);
	krit.ai_family=AF_UNSPEC;
	krit.ai_socktype=SOCK_STREAM;
	krit.ai_flags=AI_PASSIVE;

	getaddrinfo(NULL,listenport,&krit,&res);

	listenSocket=socket(res->ai_family,res->ai_socktype,res->ai_protocol);
	int v=1;
	setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR,&v, sizeof(v));

	if(bind(listenSocket,res->ai_addr,res->ai_addrlen)){
		printf("bind error");
		fflush(stdout);
	}

	listen(listenSocket,MAXCLIENT);

	fdmax=listenSocket;
	FD_ZERO(&master);
	FD_SET(listenSocket,&master);
}

int main(int argc, char **argv) {
	strcpy(szerverszamrendszer,argv[1]);
	printf("Szamrendszer %s\n",szerverszamrendszer);
	fflush(stdout);

	serverlisten();
	processloop();

	return 0;
}
